﻿using AutoMapper;
using Compass.PlanService.Domain;
using Compass.PlanService.Domain.Entities;
using Compass.PlanService.Infrastructure;
using Compass.Wasm.Shared;
using Compass.Wasm.Shared.Charts;
using Compass.Wasm.Shared.Plans;

namespace Compass.Wasm.Server.Services.Plans;
public interface IMainPlanService : IBaseService<MainPlanDto>
{
    //扩展查询
    Task<ApiResponse<MainPlanDto>> GetSingleByNumberAsync(string number);
    Task<ApiResponse<MainPlanDto>> UpdateStatusesAsync(Guid id, MainPlanDto dto);

    Task<ApiResponse<IEnumerable<MainPlanDto>>> GetAllByProjectIdAsync(Guid projectId);
    //WPF主页，计划信息统计
    Task<ApiResponse<MainPlanCountDto>> GetCountAsync();
    //MAUI
    Task<ApiResponse<IEnumerable<MainPlanDto>>> GetMauiMainPlansAsync(int skip, int take, string? search);
    //Blazor轻量化显示
    Task<ApiResponse<IEnumerable<MainPlanDto>>> GetBlazorMainPlansAsync(int year, int month, bool annual, bool fromMonth, bool allOpenIssue, bool withIssue);
    public Task<ApiResponse<IEnumerable<ChartIntDataDto>>> GetBlazorMainPlanStatusAsync(int year, int month, bool annual);
    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorDeliveryReliabilityAsync(int year);
    public Task<ApiResponse<double>> GetBlazorDeliveryReliabilityYtdAsync(int year);

    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorProductionCycleTimeAsync(int year);
    public Task<ApiResponse<double>> GetBlazorProductionCycleTimeYtdAsync(int year);

    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorFactoryCycleTimeAsync(int year);
    public Task<ApiResponse<double>> GetBlazorFactoryCycleTimeYtdAsync(int year);

    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorOrderCycleTimeAsync(int year);
    public Task<ApiResponse<double>> GetBlazorOrderCycleTimeYtdAsync(int year);

}
public class MainPlanService : IMainPlanService
{
    #region ctor
    private readonly PlanDomainService _domainService;
    private readonly IIssueService _issueService;
    private readonly PlanDbContext _dbContext;
    private readonly IPlanRepository _repository;
    private readonly IMapper _mapper;
    private readonly IEventBus _eventBus;
    private readonly IPackingListService _packingListService;


    public MainPlanService(PlanDomainService domainService, IIssueService issueService, PlanDbContext dbContext, IPlanRepository repository, IMapper mapper, IEventBus eventBus, IPackingListService packingListService)
    {
        _domainService = domainService;
        _issueService = issueService;
        _dbContext = dbContext;
        _repository = repository;
        _mapper = mapper;
        _eventBus = eventBus;
        _packingListService = packingListService;
    }
    #endregion

    #region 基本增删改查
    public async Task<ApiResponse<IEnumerable<MainPlanDto>>> GetAllAsync()
    {
        try
        {
            var models = await _repository.GetMainPlansAsync();
            var orderModels = models.OrderByDescending(x => x.FinishTime);
            var dtos = await _mapper.ProjectTo<MainPlanDto>(orderModels).ToListAsync();
            foreach (var dto in dtos)
            {
                await GetIssues(dto);
                await GetPackingListInfo(dto);
            }
            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = true, Result = dtos };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<MainPlanDto>> GetSingleAsync(Guid id)
    {
        try
        {
            var model = await _repository.GetMainPlanByIdAsync(id);
            if (model == null) return new ApiResponse<MainPlanDto> { Status = false, Message = "查询数据失败" };
            var dto = _mapper.Map<MainPlanDto>(model);
            await GetIssues(dto);
            return new ApiResponse<MainPlanDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<MainPlanDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<MainPlanDto>> AddAsync(MainPlanDto dto)
    {
        try
        {
            var model = new MainPlan(Guid.NewGuid(), dto.CreateTime, dto.Number, dto.Name, dto.Quantity, dto.ModelSummary, dto.FinishTime, dto.DrwReleaseTarget, dto.MonthOfInvoice, dto.MainPlanType, dto.Remarks, dto.Batch, dto.ItemLine, dto.Workload, dto.Value);
            await _dbContext.MainPlans.AddAsync(model);
            dto.Id = model.Id;

            //Todo:发出集成事件，绑定潜在的项目
            //var eventData = new MainPlanCreatedEvent(dto.Id.Value, dto.Name);
            //发布集成事件
            //_eventBus.Publish("PlanService.MainPlan.Created", eventData);

            return new ApiResponse<MainPlanDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<MainPlanDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<MainPlanDto>> UpdateAsync(Guid id, MainPlanDto dto)
    {
        try
        {
            var model = await _repository.GetMainPlanByIdAsync(id);
            if (model == null) return new ApiResponse<MainPlanDto> { Status = false, Message = "更新数据失败" };
            model.Update(dto);
            return new ApiResponse<MainPlanDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<MainPlanDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<MainPlanDto>> DeleteAsync(Guid id)
    {
        try
        {
            var model = await _repository.GetMainPlanByIdAsync(id);
            if (model == null) return new ApiResponse<MainPlanDto> { Status = false, Message = "删除数据失败" };
            model.SoftDelete();//软删除
            return new ApiResponse<MainPlanDto> { Status = true };
        }
        catch (Exception e)
        {
            return new ApiResponse<MainPlanDto> { Status = false, Message = e.Message };
        }
    }

    #endregion

    #region 扩展
    public async Task<ApiResponse<MainPlanDto>> GetSingleByNumberAsync(string number)
    {
        try
        {
            var model = await _repository.GetMainPlanByNumberAsync(number);
            if (model == null) return new ApiResponse<MainPlanDto> { Status = false, Message = "查询数据失败" };
            var dto = _mapper.Map<MainPlanDto>(model);
            await GetIssues(dto);
            return new ApiResponse<MainPlanDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<MainPlanDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<MainPlanDto>> UpdateStatusesAsync(Guid id, MainPlanDto dto)
    {
        try
        {
            var model = await _repository.GetMainPlanByIdAsync(id);
            if (model == null) return new ApiResponse<MainPlanDto> { Status = false, Message = "更新数据失败" };
            model.UpdateStatuses(dto);
            return new ApiResponse<MainPlanDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<MainPlanDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<IEnumerable<MainPlanDto>>> GetAllByProjectIdAsync(Guid projectId)
    {
        try
        {
            var models = await _repository.GetMainPlansByProjectIdAsync(projectId);
            var dtos = await _mapper.ProjectTo<MainPlanDto>(models).ToListAsync();
            foreach (var dto in dtos)
            {
                await GetIssues(dto);
                await GetPackingListInfo(dto);
            }
            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = true, Result = dtos };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = false, Message = e.Message };
        }
    }

    /// <summary>
    /// 查询项目的统计信息
    /// </summary>
    /// <returns></returns>
    public async Task<ApiResponse<MainPlanCountDto>> GetCountAsync()
    {
        try
        {
            //所有项目
            var dtos = (await GetAllAsync()).Result;
            MainPlanCountDto summary = new();
            summary.Sum = dtos.ToList().Count;//总项目数
            summary.PlanCount = dtos.Count(x => x.Status == MainPlanStatus_e.计划);
            summary.DrawingCount = dtos.Count(x => x.Status == MainPlanStatus_e.制图);
            summary.ProductionCount = dtos.Count(x => x.Status == MainPlanStatus_e.生产);
            summary.WarehousingCount = dtos.Count(x => x.Status == MainPlanStatus_e.入库);
            summary.ShippingCount = dtos.Count(x => x.Status == MainPlanStatus_e.发货);
            summary.CompletedCount = dtos.Count(x => x.Status == MainPlanStatus_e.结束);

            return new ApiResponse<MainPlanCountDto> { Status = true, Result = summary };
        }
        catch (Exception e)
        {
            return new ApiResponse<MainPlanCountDto> { Status = false, Message = e.Message };
        }
    }
    #endregion

    #region MAUI
    public async Task<ApiResponse<IEnumerable<MainPlanDto>>> GetMauiMainPlansAsync(int skip, int take, string? search)
    {
        try
        {
            var models = await _repository.GetMainPlansAsync();
            var orderModels = models.OrderByDescending(x => x.FinishTime);
            var dtos = await orderModels.Where(x => string.IsNullOrEmpty(search) || x.Number.ToLower().Contains(search.ToLower())
                    || x.Name.ToLower().Contains(search.ToLower()))
                .Skip(skip)
                .Take(take)
                .Select(x => new MainPlanDto()
                {
                    //轻量化信息
                    Id = x.Id,
                    Number = x.Number,
                    Name = x.Name,
                    FinishTime = x.FinishTime,
                    WarehousingTime = x.WarehousingTime,
                    ShippingTime = x.ShippingTime,
                    ClosedTime = x.ClosedTime,
                    Status = x.Status,
                }).ToListAsync();
            //检查是否包含装箱清单
            foreach (var dto in dtos)
            {
                await GetPackingListInfo(dto);
            }

            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = true, Result = dtos };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = false, Message = e.Message };
        }
    }


    #endregion

    #region Blazor，尽量有针对性的传递少的信息
    public async Task<ApiResponse<IEnumerable<MainPlanDto>>> GetBlazorMainPlansAsync(int year, int month, bool annual, bool fromMonth, bool openIssue, bool withIssue)
    {
        try
        {
            var models = await _repository.GetMainPlansAsync();
            //2024.07.08,添加包含所有异常项目
            var ids = new List<Guid>();
            if (openIssue) ids.AddRange(await _repository.GetMainPlanIdsByOpenIssueAsync());

            //查询信息：搜索，全年，本月往后，年，月
            //（1.全年||2.本月以后||3.当年当月）
            var startDate = new DateTime(year, month, 1);
            var dtos = await models.Where(
                x => ids.Contains(x.Id) ||
                      (annual && x.MonthOfInvoice.Year==year) ||
                              (fromMonth && x.MonthOfInvoice>=startDate) ||
                              (x.MonthOfInvoice.Year==year && x.MonthOfInvoice.Month==month)
                ).Select(x => new MainPlanDto
                {
                    //主页
                    Id = x.Id,
                    Status = x.Status,
                    Batch=x.Batch,
                    Number = x.Number,
                    ProjectId = x.ProjectId,
                    Name = x.Name,
                    CreateTime = x.CreateTime,
                    DrwReleaseTarget = x.DrwReleaseTarget,
                    DrwReleaseTime = x.DrwReleaseTime,
                    FinishTime = x.FinishTime,
                    WarehousingTime = x.WarehousingTime,
                    ShippingTime = x.ShippingTime,
                    ClosedTime = x.ClosedTime,
                    //计划页
                    Quantity = x.Quantity,
                    ModelSummary = x.ModelSummary,
                    MainPlanType = x.MainPlanType,
                    Remarks = x.Remarks

                })
                .OrderByDescending(x => x.FinishTime).ToListAsync();
            //显示信息：状态	分批	项目编号	项目名称	计划发图	发图时间	计划完工	入库时间	发货时间
            //装箱信息(HavePackingList)	总结问题(AllIssueClosed,)	总结经验

            //检查是否包含装箱清单/异常信息/经验教训
            foreach (var dto in dtos)
            {
                await GetPackingListInfo(dto);
                await GetIssueInfo(dto, withIssue);
                //todo:LessonInfo
            }

            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = true, Result = dtos.OrderBy(x => x.AllIssueClosed) };//将异常项目置顶
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<MainPlanDto>> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<IEnumerable<ChartIntDataDto>>> GetBlazorMainPlanStatusAsync(int year, int month, bool annual)
    {
        try
        {
            var models = await _repository.GetMainPlansAsync();
            var status = await models.Where(
                    x => (annual && x.MonthOfInvoice.Year==year) ||
                         (x.MonthOfInvoice.Year==year && x.MonthOfInvoice.Month==month)
                ).Select(x => x.Status.ToString()).ToListAsync();
            var dtos = Enum.GetNames(typeof(MainPlanStatus_e)).Select(s => new ChartIntDataDto { Label = s, Value = status.Count(x => x == s) }).ToList();
            return new ApiResponse<IEnumerable<ChartIntDataDto>> { Status = true, Result = dtos };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<ChartIntDataDto>> { Status = false, Message = e.Message };
        }
    }

    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorDeliveryReliabilityAsync(int year)
    {
        try
        {
            //delivery reliability rate = on time project hoods’ Qty / total hoods’ Qty monthly
            //On time,WarehousingTime<=FinishTime
            var dtos = Enumerable.Range(1, 12).Select(m => new ChartDoubleDataDto { Label = m.ToString(), Value =  _repository.GetDeliveryReliabilityByMonth(year, m)});

            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = true, Result = dtos });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = false, Message = e.Message });
        }
    }

    public Task<ApiResponse<double>> GetBlazorDeliveryReliabilityYtdAsync(int year)
    {
        try
        {
            //delivery reliability rate = on time project hoods’ Qty / total hoods’ Qty monthly
            //On time,WarehousingTime<=FinishTime
            return Task.FromResult(new ApiResponse<double> { Status = true, Result = _repository.GetDeliveryReliabilityByYear(year) });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<double> { Status = false, Message = e.Message });
        }
    }

    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorProductionCycleTimeAsync(int year)
    {
        try
        {
            var dtos = Enumerable.Range(1, 12).Select(m => new ChartDoubleDataDto { Label = m.ToString(), Value =  _repository.GetProductionCycleTimeByMonth(year, m) });
            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = true, Result = dtos });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = false, Message = e.Message });
        }
    }

    public Task<ApiResponse<double>> GetBlazorProductionCycleTimeYtdAsync(int year)
    {
        try
        {
            return Task.FromResult(new ApiResponse<double> { Status = true, Result = _repository.GetProductionCycleTimeByYear(year) });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<double> { Status = false, Message = e.Message });
        }
    }

    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorFactoryCycleTimeAsync(int year)
    {
        try
        {
            var dtos = Enumerable.Range(1, 12).Select(m => new ChartDoubleDataDto { Label = m.ToString(), Value =  _repository.GetFactoryCycleTimeByMonth(year, m) });
            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = true, Result = dtos });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = false, Message = e.Message });
        }
    }

    public Task<ApiResponse<double>> GetBlazorFactoryCycleTimeYtdAsync(int year)
    {
        try
        {
            return Task.FromResult(new ApiResponse<double> { Status = true, Result = _repository.GetFactoryCycleTimeByYear(year) });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<double> { Status = false, Message = e.Message });
        }
    }

    public Task<ApiResponse<IEnumerable<ChartDoubleDataDto>>> GetBlazorOrderCycleTimeAsync(int year)
    {
        try
        {
            var dtos = Enumerable.Range(1, 12).Select(m => new ChartDoubleDataDto { Label = m.ToString(), Value =  _repository.GetOrderCycleTimeByMonth(year, m) });
            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = true, Result = dtos });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<IEnumerable<ChartDoubleDataDto>> { Status = false, Message = e.Message });
        }
    }

    public Task<ApiResponse<double>> GetBlazorOrderCycleTimeYtdAsync(int year)
    {
        try
        {
            return Task.FromResult(new ApiResponse<double> { Status = true, Result = _repository.GetOrderCycleTimeByYear(year) });
        }
        catch (Exception e)
        {
            return Task.FromResult(new ApiResponse<double> { Status = false, Message = e.Message });
        }
    }
    #endregion

    private async Task GetPackingListInfo(MainPlanDto dto)
    {
        //此逻辑不对，应该是看有没有packinglist
        var pkList = await _repository.GetPackingListByIdAsync(dto.Id.Value);
        dto.HavePackingList = pkList!=null;
    }

    private async Task GetIssueInfo(MainPlanDto dto, bool withIssue)
    {
        //此逻辑不对，应该是看有没有packinglist
        var issueDtos = (await _issueService.GetAllByMainPlanIdAsync(dto.Id.Value)).Result.ToList();
        if (withIssue)
        {
            dto.IssueDtos.Clear();
            dto.IssueDtos.AddRange(issueDtos);
        }

        dto.AllIssueClosed = issueDtos.All(x => x.IsClosed);
        if (!dto.AllIssueClosed)
        {
            dto.IssueTitles = string.Join(',', issueDtos.Where(x => !x.IsClosed).Select(x => x.Title));
        }
    }

    //todo:有待淘汰
    private async Task GetIssues(MainPlanDto dto)
    {
        dto.IssueDtos = (await _issueService.GetAllByMainPlanIdAsync(dto.Id.Value)).Result.ToList();
        dto.AllIssueClosed = dto.IssueDtos.All(x => x.IsClosed);
        if (!dto.AllIssueClosed)
        {
            dto.IssueTitles = string.Join(',', dto.IssueDtos.Where(x => !x.IsClosed).Select(x => x.Title));
        }
    }
}